<!--
 * @Description:
 * @version:
 * @Author: E-CHOOSEUS R&D
 * @LastEditors: E-CHOOSEUS R&D
-->
<template>
  <div id="aiDoc">
    <div v-show="!printing" id="preRenderDoc">
      <div
        ref="docHeader"
        class="doc-header-area"
        :style="{ width: pageA4['297mm'] + 'px' }"
      >
        <doc-header :printing="printing" :docData="docData" />
      </div>
      <pre-render-page
        :columns="titleColumns"
        :title-tree="treeColumns"
        :table-list="tableList"
        :docData="docData"
        :activeDate="activeDate"
      />
      <div ref="docFooter" class="doc-footer-area">
        <DocFooter />
      </div>
    </div>

    <div
      v-for="(item, index) in computeString"
      v-show="!printing"
      :key="index"
      :ref="e => (refs[index] = e)"
      class="compute-box"
      :class="index"
      :style="{ width: item.width + 'px' }"
    ></div>

    <div v-for="(item, idx) in subPagesConfigList" :key="idx" class="pages-row">
      <icr-partial-page
        v-for="(rItem, rIdx) in item.rowList"
        :key="rIdx"
        :ref="e => (icrPartialPageRefs[idx + '_' + rIdx] = e)"
        :style="{ display: printing ? 'block' : 'inline-block' }"
        :title-columns="rItem.titleColumns"
        :data-type="rItem.rowType"
        :data-list="rItem.rData"
        :page-config="rItem"
        :fixed-cell-w="rItem._fixedW"
        :filled-cell-w="rItem._filledW"
        :printing="printing"
        :page-stretch-w="rItem.pageStretchW"
        :page-height="pageHeight"
        :docData="docData"
        :docTopExtendPage="item.docTopExtendPage"
        :activeDate="activeDate"
        @edit="e => handleEdit(e, idx)"
        @saveCellData="e => handleDialogShow(e, idx + '_' + rIdx)"
      />
    </div>
    <el-dialog title="编辑" :visible.sync="dialogVisible" width="500px">
      <el-form ref="form" label-width="auto">
        <el-form-item>
          <template slot="label">
            <div>{{ curCellData.title }}</div>
            <!-- <div>{{ curCellData.propUnit }}</div> -->
          </template>
          <template v-if="curCellData.dictValue === 'yx-bqgc'">
            <el-input
              v-model="curCellData.val"
              type="textarea"
              :rows="20"
              placeholder="请输入"
            ></el-input>
          </template>
          <template v-else>
            <el-input v-model="curCellData.val" placeholder="请输入"></el-input>
          </template>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="saveCellData">保存</el-button>
          <el-button @click="dialogVisible = false">取消</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
    <el-dialog title="签名" :visible.sync="dialogVisibleC" width="500px">
      <el-form ref="form" label-width="auto">
        <el-form-item>
          <el-button type="primary" @click="saveCellData">确认签名</el-button>
          <el-button @click="saveCellData('del')">取消签名</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>
  </div>
</template>

<script>
import { endOfDay, format, startOfDay } from 'date-fns'
import { cloneDeep } from 'lodash-unified'
import {
  computed,
  defineComponent,
  nextTick,
  reactive,
  set,
  toRefs,
  watch
} from 'vue'
import workerpool from 'workerpool'

import { Doc } from '@/api/doc'
import {
  getCareData as getIcrDocRecordList,
  getCareTitleTree as getIcrDocConfigTreeList,
  savOneCareData
} from '@/api/manage/doc-IntensiveCareRecord'
import { withPermission } from '@/directives/v-has'
import { useSign } from '@/hooks'
import {
  getElementFnFromInstance,
  getStoreFromInstance
} from '@/utils/instance'

import {
  getPagesColumnAndRData,
  getPagesXRenderList,
  getPagingDataList,
  getRenderRowDefault,
  getRespList,
  matchKeys,
  parseTitleColumns,
  toFlatData
} from './adapter'
/* ------------------------------------------------------------------------------------------------------------------ */
/*                                                        代码改造                                                        */
/* ------------------------------------------------------------------------------------------------------------------ */
import {
  getPreRenderCfgTitle,
  resolveDataRowsAndValue,
  setCfgTitleSymbolAndGetKeyInfo
} from './components/adapter-pro'
import DocFooter from './components/docFooter.vue'
import DocHeader from './components/docHeader.vue'
import {
  getRenderedTitleColumns,
  optimizePagesColumnWidth,
  optimizeTitleColumns,
  TitleColumnsHeightStrategy,
  updateTitleColumnsLayoutData
} from './components/layoutCompute-pro'
import preRenderPage from './components/preRenderPage.vue'
import IcrPartialPage from './icrPartialPage.vue'
import {
  getDocTopExtendPages,
  getPagesYDataPagingInfo,
  getRowRenderHeight,
  pageA4,
  pageBaseInfo,
  parseColumnListToTree
} from './layout-compute'
import { getPagesColumnWorker } from './worker'

const pool = workerpool.pool()

export default defineComponent({
  name: 'AiDocPage',
  components: {
    preRenderPage,
    IcrPartialPage,
    DocHeader,
    DocFooter
  },
  props: {
    username: {
      type: String,
      default: ''
    },
    printing: {
      type: Boolean,
      default: false
    },
    activeDate: {
      type: Array,
      default: () => []
    }
  },
  emits: ['changeLoading2', 'getOperationDrawerForm', 'edit'],
  setup(props, { emit }) {
    const state = reactive({
      matchKeys,
      pageA4,
      fullList: [], // 全量数据集
      titleColumns: [], // 表头列
      treeColumns: null, // * 新的计算表头
      computedColumns: [], // 计算出来的表头
      totalRows: 0, // 总行数
      tableList: [], // 表格渲染行
      theadHeight: 0, // 表头高度
      docHeadHeight: 0, // 文书表头高度
      docFootHeight: 0, // 文书底部高度
      subPagesConfigList: [], // 分页信息列表
      pageHeight: pageA4['210mm'],
      computeString: {},
      lastPatCurId: null,
      refs: {},
      docData: {
        doc: {},
        docItems: [],
        scoreRecord: [],
        respList: []
      }, // 顶部评分、简要病史、过敏史等数据
      docTopExtendPages: [],
      icrPartialPageRefs: {},
      dialogVisible: false,
      dialogVisibleC: false,
      curCellData: {},
      curRefIndex: '',
      cellVIdx: -1,
      cellHIdx: -1
    })

    const store = getStoreFromInstance()
    const { $message } = getElementFnFromInstance()
    const { queryUserSignByName } = useSign()

    const patCur = computed(() => store.getters.patCur)
    const user = computed(() => store.getters.user)

    const isHistory = computed(() => store.getters.isHistory)

    // 保存单元格数据
    function saveCellData(operateType = 'add') {
      // 竖向分页下标
      const idx = state.curRefIndex.split('_')[0]
      // 横向分页下标
      const rIdx = state.curRefIndex.split('_')[1]
      // 当前选中单元格的code字段名
      const matchKey = matchKeys[state.curCellData.dictValue]
      let codes = []
      if (
        ['yx-crl-in', 'yx-crl-out', 'yx-bqgc', 'operater', 'yx-diy'].includes(
          state.curCellData.dictValue
        )
      ) {
        // 出入量、病情观察直接把dictValue设为code
        codes = [state.curCellData.dictValue]
      } else if (
        ['yx-ysjl', 'yx-yzzxjl'].includes(state.curCellData.dictValue)
      ) {
        // 约束记录、特殊药物把dataCode设为code
        codes = [state.curCellData.dataCode]
      } else {
        // 其他项获取对应code
        codes = state.curCellData[matchKey]
      }
      const splicer = state.curCellData.splicer || null // 分隔符
      let ids = [] // 数据id
      if (state.curCellData.id) {
        ids = state.curCellData.id.split(splicer)
      }
      let valArr = []
      // 当前行数据
      const rData =
        state.subPagesConfigList[idx].rowList[rIdx].rData[state.cellVIdx].rData
      if (state.curCellData.dictValue === 'yx-ysjl') {
        const val = []
        // 约束记录保存编辑的时候需要把当前行所有的约束记录数据整合成一条
        // 约束记录各列的数据是从一条数据里的不同字段获取的
        // 一行可能有多条数据
        const setValData = function (v) {
          if (v.val) {
            v.val.split('/').forEach((item, index) => {
              if (!val[index]) {
                val[index] = {
                  restrictPositionName: [],
                  restrictToolName: [],
                  restrictBsName: '',
                  restrictRelaxValue: '',
                  restrictRelaxUnit: '',
                  restrictPfName: ''
                }
              }
              if (v[matchKey].includes('ysjl-fieldCode-0')) {
                val[index].restrictPositionName = item ? item.split(';') : []
              } else if (v[matchKey].includes('ysjl-fieldCode-1')) {
                val[index].restrictToolName = item ? item.split(';') : []
              } else if (v[matchKey].includes('ysjl-fieldCode-2')) {
                val[index].restrictBsName = item
              } else if (v[matchKey].includes('ysjl-fieldCode-3')) {
                if (v.val) {
                  val[index].restrictRelaxValue =
                    item && !Number.isNaN(parseFloat(item))
                      ? parseFloat(item) + ''
                      : ''
                  val[index].restrictRelaxUnit = item?.replace(
                    val[index].restrictRelaxValue,
                    ''
                  )
                }
              } else if (v[matchKey].includes('ysjl-fieldCode-4')) {
                val[index].restrictPfName = item
              }
            })
          }
        }
        // 遍历当前行，对约束记录的数据做处理
        rData.forEach(v => {
          if (v.dictValue === 'yx-ysjl') {
            if (v._uuid === state.curCellData._uuid) {
              setValData(state.curCellData)
            } else {
              if (v.val) {
                setValData(v)
              }
            }
          }
        })
        setValData(state.curCellData)
        valArr = [JSON.stringify(val)]
      } else if (state.curCellData.dictValue === 'yx-yzzxjl') {
        const val = []
        // 特殊药物保存编辑的时候需要把当前行所有的特殊药物数据整合成一条
        // 因为是整合成一条数据保存，所以当前行的特殊药物只要有一个id，就算编辑
        rData.forEach(v => {
          if (v.dictValue === 'yx-yzzxjl') {
            if (v._uuid === state.curCellData._uuid) {
              if (state.curCellData.val) {
                val.push({
                  medicationName: state.curCellData.val.split(';')[0],
                  exeSpeed: state.curCellData.val.split(';')[1]
                })
              }
            } else {
              if (v.val) {
                val.push({
                  medicationName: v.val.split(';')[0],
                  exeSpeed: v.val.split(';')[1]
                })
              }
            }

            if (v.id) {
              ids = [v.id]
            }
          }
        })
        if (val.length === 0 && state.curCellData.val) {
          val.push({
            medicationName: state.curCellData.val.split(';')[0],
            exeSpeed: state.curCellData.val.split(';')[1]
          })
        }
        valArr = [JSON.stringify(val)]
      } else if (state.curCellData.dictValue === 'operater') {
        if (operateType === 'del') {
          valArr = ['']
        } else {
          valArr = [user.value.name]
        }
      } else {
        valArr = state.curCellData.val
          ? state.curCellData.val.split(splicer)
          : []
      }
      const specialCodes = {
        'yx-crl-in': 'sumInValue',
        'yx-crl-out': 'sumOutValue',
        'yx-bqgc': 'bqgc_content',
        'yx-diy': state.curCellData.title
      }
      // 一个code相当于一个数据源，所以需要分多次请求接口
      codes.forEach((v, index) => {
        const params = {
          patientIdent: patCur.value.patientIdent,
          hospitalNumber: patCur.value.hospitalNumber,
          moduleType:
            state.curCellData.dictValue === 'operater'
              ? 'yx-sign'
              : state.curCellData.dictValue,
          fieldName: state.curCellData.title,
          fieldCode: specialCodes[v] || v,
          fieldValue: valArr[index] || '',
          recTime: +new Date(state.curCellData.date),
          dataSource: 2
        }
        if (ids[index]) {
          params.id = ids[index]
        }
        savOneCareData(params).then(async () => {
          const rowList = state.subPagesConfigList[idx].rowList // 当前行数据
          const curRowInLastPage =
            rowList[rowList.length - 1].rData[state.cellVIdx].rData // 签名列所在的数据
          if (state.curCellData.dictValue !== 'operater') {
            // 修改成功后签名变为当前用户
            await handleOperaterChange(curRowInLastPage, state.curCellData.date)
          }
          queryDocRenderData()
          state.dialogVisible = false
          state.dialogVisibleC = false
        })
      })
    }

    function handleOperaterChange(curRowInLastPage, date) {
      const operaterItem = curRowInLastPage.find(
        v => v.dictValue === 'operater'
      )
      const params = {
        patientIdent: patCur.value.patientIdent,
        hospitalNumber: patCur.value.hospitalNumber,
        moduleType: 'yx-sign',
        fieldName: '签名',
        fieldCode: 'operater',
        fieldValue: user.value.name,
        recTime: +new Date(date),
        dataSource: 2
      }
      if (operaterItem.id) {
        params.id = operaterItem.id
      }
      return savOneCareData(params)
    }

    function handleDialogShow(
      { hItem, titleColumnItem, dateItem, vIdx, hIdx },
      refIndex
    ) {
      if (hItem.dictValue === 'operater')
        state.curCellData = {
          ...hItem,
          title: titleColumnItem.title,
          propUnit: titleColumnItem.propUnit,
          date: dateItem.val
        }

      state.curRefIndex = refIndex
      state.cellVIdx = vIdx
      state.cellHIdx = hIdx
      state.dialogVisibleC = true
    }

    function handleEdit(e, idx) {
      let rowList = state.subPagesConfigList[idx].rowList
      let $event = e
      for (let i = idx; i >= 0; i--) {
        let f = false
        const rData = state.subPagesConfigList[i].rowList[0].rData
        let startIndex = rData.length - 1
        if (i === idx) {
          startIndex = e
        }
        for (let j = startIndex; j >= 0; j--) {
          const dateValueCol = rData[j].rData.find(
            v => v.dictValue === 'date_value'
          )
          if (dateValueCol.val) {
            rowList = state.subPagesConfigList[i].rowList
            $event = j
            f = true
            break
          }
        }
        if (f) {
          break
        }
      }
      emit('edit', $event, rowList)
    }

    function handleTime(time, type) {
      if (type === 'rk' && patCur.value.startRkTime) {
        return time < patCur.value.startRkTime ? patCur.value.startRkTime : time
      } else if (type === 'ck' && patCur.value.endCkTime) {
        return time > patCur.value.endCkTime ? patCur.value.endCkTime : time
      }
      return time
    }

    function initData() {
      emit('changeLoading2', true)
      setTimeout(() => {
        // getDocData()
        queryDocRenderData()
      }, 200)
    }

    function queryDocRenderData() {
      if (!patCur.value) {
        return
      }
      const startTime = props.activeDate[0]
      const endTime = props.activeDate[1]
      const params1 = {
        hospitalNumber: patCur.value.hospitalNumber,
        startTime: patCur.value.startRkTime || '',
        endTime: patCur.value.endCkTime,
        isHistory: isHistory.value ? 0 : 1,
        patientIdent: patCur.value.patientIdent,
        docType: 1
      }
      const params2 = {
        hospitalNumber: patCur.value.hospitalNumber,
        patientIdent: patCur.value.patientIdent,
        startTime: handleTime(startTime, 'rk'),
        endTime: handleTime(endTime, 'ck')
      }
      const params3 = {
        hospitalNumber: patCur.value.hospitalNumber,
        patientIdent: patCur.value.patientIdent,
        rkTime: patCur.value.startRkTime,
        recordTime: new Date().getTime()
      }
      function mergeSpecialColumn(arr) {
        for (let i = 0; i < arr.length; i++) {
          if (
            arr[i].titleType == 1 &&
            arr[i].childNode &&
            arr[i].childNode.length > 0
          ) {
            const obsvCode = [],
              pgId = [],
              itemCode = [],
              pgType = [],
              enumMap = {}
            let obsvDataType
            arr[i].childNode.forEach(item => {
              if (item.obsvCode) {
                obsvCode.push(item.obsvCode)
              }
              if (item.pgId) {
                pgId.push(item.pgId)
              }
              if (item.itemCode) {
                itemCode.push(item.itemCode)
              }
              if (item.pgType) {
                pgType.push(item.pgType)
              }
              if (item.obsvDataType) {
                obsvDataType = item.obsvDataType
              }
              if (item.enumMap) {
                enumMap[item.obsvCode] = {
                  ...JSON.parse(item.enumMap),
                  title: item.title
                }
              }
            })
            arr[i].obsvCode = obsvCode
            arr[i].pgId = pgId
            arr[i].itemCode = itemCode
            arr[i].pgType = pgType
            arr[i].obsvDataType = obsvDataType
            // console.log(enumMap)
            arr[i].enumMap = enumMap
            arr[i].childNode = []
          }
          if (arr[i].dictValue === 'yx-diy') {
            arr[i].itemCode = arr[i].title
          }
          if (arr[i].childNode && arr[i].childNode.length > 0) {
            mergeSpecialColumn(arr[i].childNode)
          }
        }
      }
      Promise.all([
        getIcrDocConfigTreeList(params1),
        getIcrDocRecordList(params2)
      ]).then(async ([{ data: cfgData }, { data: renderData }]) => {
        renderData = mergeData(renderData)
        let specialMedicineMax = 1
        renderData?.forEach(v => {
          // 当有特殊药物或者约束记录时，拆分为多条数据
          for (const key in v) {
            const item = v[key]
            const arr = []
            let specialMedicineNum = 0
            item.forEach(v2 => {
              if (v2.dataCode === 'special_medicine_list') {
                v2['yzzxjl-fieldValue'].forEach((v3, index3) => {
                  arr.push({
                    dataCode: 'special_medicine_item',
                    ['yzzxjl-fieldCode']:
                      'yzzxjl-fieldCode-' + specialMedicineNum,
                    ['yzzxjl-fieldValue']: [
                      v3.medicationName,
                      v3.exeSpeed
                    ].join(';'),
                    ['yzzxjl-recordId']: v2['yzzxjl-recordId']
                  })
                  specialMedicineNum++
                })
              } else if (v2.dataCode === 'restrict_list') {
                v2['ysjl-fieldValue'].forEach((v3, index3) => {
                  arr.push(
                    ...[
                      {
                        dataCode: 'restrict_item',
                        ['ysjl-fieldCode']: 'ysjl-fieldCode-0',
                        ['ysjl-fieldValue']: v3.restrictPositionName
                          ? v3.restrictPositionName.join(';')
                          : '',
                        ['ysjl-recordId']: v2['ysjl-recordId']
                      },
                      {
                        dataCode: 'restrict_item',
                        ['ysjl-fieldCode']: 'ysjl-fieldCode-1',
                        ['ysjl-fieldValue']: v3.restrictToolName
                          ? v3.restrictToolName.join(';')
                          : '',
                        ['ysjl-recordId']: v2['ysjl-recordId']
                      },
                      {
                        dataCode: 'restrict_item',
                        ['ysjl-fieldCode']: 'ysjl-fieldCode-2',
                        ['ysjl-fieldValue']: v3.restrictBsName,
                        ['ysjl-recordId']: v2['ysjl-recordId']
                      },
                      {
                        dataCode: 'restrict_item',
                        ['ysjl-fieldCode']: 'ysjl-fieldCode-3',
                        ['ysjl-fieldValue']:
                          v3.restrictRelaxValue + v3.restrictRelaxUnit,
                        ['ysjl-recordId']: v2['ysjl-recordId']
                      },
                      {
                        dataCode: 'restrict_item',
                        ['ysjl-fieldCode']: 'ysjl-fieldCode-4',
                        ['ysjl-fieldValue']: v3.restrictPfName,
                        ['ysjl-recordId']: v2['ysjl-recordId']
                      }
                    ]
                  )
                })
              }
            })
            item.push(...arr)
            specialMedicineMax = Math.max(
              specialMedicineMax,
              specialMedicineNum
            )
          }
        })
        // 表头数据插入相应的特殊药物和约束记录列
        let specialMedicineColIndex = -1
        cfgData.forEach((v, index) => {
          if (v.dictValue === 'yx-yzzxjl') {
            const childNode = []
            for (let i = 0; i < specialMedicineMax; i++) {
              childNode.push({
                ...cloneDeep(v),
                itemCode: ['yzzxjl-fieldCode-' + i],
                title: ['药名', '走速'].join(';'),
                dataCode: 'special_medicine_list'
              })
            }
            if (childNode.length === 0) {
              specialMedicineColIndex = index
            }
            v.titleType = 0
            v.propUnit = ''
            v.childNode = childNode
          } else if (v.dictValue === 'yx-ysjl') {
            const titles = [
              '约束部位',
              '约束工具',
              '肢体血循',
              '约束中断放松时间',
              '约束部位皮肤情况'
            ]
            const childNode = []
            for (let i = 0; i < 5; i++) {
              if (![0, 4].includes(i)) {
                // 约束记录只显示约束部位和约束部位皮肤情况
                continue
              }
              childNode.push({
                ...cloneDeep(v),
                itemCode: ['ysjl-fieldCode-' + i],
                title: titles[i],
                splicer: '/',
                dataCode: 'restrict_list'
              })
            }
            v.titleType = 0
            v.propUnit = ''
            v.childNode = childNode
          }
        })
        // 当特殊药物列药物数量为0，不显示该列
        if (specialMedicineColIndex >= 0) {
          cfgData.splice(specialMedicineColIndex, 1)
        }
        emit('getOperationDrawerForm', {
          cfgData: cloneDeep(cfgData)
        })
        if (cfgData) {
          mergeSpecialColumn(cfgData)
        }
        // 当表头只有日期和签名时，增加一列空白列
        let needAddEmptyCol = true
        cfgData.forEach(item => {
          if (
            item.dictValue !== 'operater' &&
            item.dictValue !== 'date_value'
          ) {
            needAddEmptyCol = false
          }
        })
        if (needAddEmptyCol) {
          const cloneItem = cloneDeep(cfgData[cfgData.length - 1])
          cloneItem.title = ''
          cloneItem.dictValue = 'unknown'
          cfgData.splice(cfgData.length - 1, 0, cloneItem)
        }
        // state.docData.respList = getRespList(cloneDeep(renderData))
        const names = new Set()
        renderData?.forEach(v => {
          for (const key in v) {
            const item = v[key]
            item?.forEach(v2 => {
              if (v2['sign-fieldCode'] === 'operater') {
                names.add(v2['sign-fieldValue'])
              }
            })
          }
        })
        const namesArray = Array.from(names)
        if (namesArray.length > 0) {
          queryUserSignByName(namesArray, 'nursingDocument', 12)
        }

        startRenderActivity(cloneDeep(cfgData), cloneDeep(renderData))
      })
    }

    // 合并出入量数据 添加大便次数统计
    function mergeData(data_) {
      const data = sortByDataSourceId(data_) // 根据 diy-dataSourceId 排序
      const result = []

      data.forEach(entry => {
        const timeKey = Object.keys(entry)[0] // 获取时间点键
        const records = entry[timeKey]

        const mergedMap = {} // 存储合并后的数据
        let fecesCount = 0 // 记录大便次数

        records.forEach(record => {
          const {
            dataCode,
            'diy-fieldCode': diyFieldCode,
            'diy-fieldValue': diyFieldValue,
            ...rest
          } = record

          // 构造合并的唯一键
          const mergeKey = `${dataCode}-${diyFieldCode}`

          if (!mergedMap[mergeKey]) {
            // 如果尚未存在该合并键，初始化一个新对象
            mergedMap[mergeKey] = {
              ...rest,
              dataCode,
              'diy-fieldCode': diyFieldCode,
              'diy-fieldValue': '',
              recTime: record.recTime,
              operator: record.operator
            }
          }

          // 拼接 diy-fieldValue，用分号分隔
          if (mergedMap[mergeKey]['diy-fieldValue']) {
            mergedMap[mergeKey]['diy-fieldValue'] += `;${diyFieldValue}`
          } else {
            mergedMap[mergeKey]['diy-fieldValue'] = diyFieldValue
          }

          // 检测出量名称是否包含“大便”
          if (
            dataCode === '出量名称' &&
            diyFieldValue &&
            diyFieldValue.includes('大便')
          ) {
            fecesCount++
          }
        })

        // 如果检测到大便次数，插入一条“大便次数”记录
        if (fecesCount > 0) {
          const timePointRecord = Object.values(mergedMap).find(r => r.recTime) // 找到当前时间点的任意记录以获取 recTime 和 operator
          if (timePointRecord) {
            const { recTime, operator, createTime } = timePointRecord
            mergedMap[`大便次数-自定义键`] = {
              recTime,
              dataCode: '大便次数',
              operator,
              'diy-fieldCode': '大便次数',
              'diy-fieldValue': fecesCount.toString(),
              createTime
            }
          }
        }

        // 将合并后的数据添加到结果数组中
        Object.values(mergedMap).forEach(mergedRecord => {
          result.push({
            [timeKey]: [mergedRecord] // 保留时间点作为键
          })
        })
      })

      // 重组数据结构，将相同时间点的记录合并
      const finalResult = {}
      result.forEach(entry => {
        const timeKey = Object.keys(entry)[0]
        if (!finalResult[timeKey]) {
          finalResult[timeKey] = []
        }
        finalResult[timeKey].push(...entry[timeKey])
      })

      // 转换回目标格式
      const formattedResult = Object.entries(finalResult).map(
        ([timeKey, records]) => ({
          [timeKey]: records
        })
      )

      return formattedResult
    }

    // 出入量数据-根据 diy-dataSourceId 排序
    function sortByDataSourceId(data) {
      const flattenedData = data.flatMap(item => {
        const timeKey = Object.keys(item)[0]
        return item[timeKey].map(record => ({
          ...record,
          timeKey
        }))
      })

      flattenedData.sort((a, b) => {
        const dataSourceIdA = a['diy-dataSourceId'] || ''
        const dataSourceIdB = b['diy-dataSourceId'] || ''
        if (dataSourceIdA < dataSourceIdB) return -1
        if (dataSourceIdA > dataSourceIdB) return 1
        return 0
      })

      const sortedGroupedData = {}
      flattenedData.forEach(record => {
        const originalItem = data.find(
          item => Object.keys(item)[0] === record.timeKey
        )
        if (originalItem) {
          const timeKey = Object.keys(originalItem)[0]
          if (!sortedGroupedData[timeKey]) {
            sortedGroupedData[timeKey] = []
          }
          sortedGroupedData[timeKey].push(record)
        }
      })

      return Object.entries(sortedGroupedData).map(([timeKey, records]) => ({
        [timeKey]: records.map(record => {
          const { timeKey: _, ...cleanedRecord } = record
          return cleanedRecord
        })
      }))
    }

    /**
     * @description 整个处理过程如下
     */
    function startRenderActivity(cfgTitle, cfgData) {
      state.subPagesConfigList = []
      /**
       * * 流程一: 渲染关键信息汇整
       */
      const {
        treeColumnMap,
        leafMap,
        docHeadHeight,
        docFootHeight,
        totalDataRows
      } = setCfgTitleSymbolAndGetKeyInfo(cfgTitle, {
        docHeadSelector: '#preRenderDoc .doc-header-area',
        docFootSelector: '#preRenderDoc .doc-footer-area'
      })
      state.docHeadHeight = docHeadHeight // * 此处得到文书头部高度
      state.docFootHeight = docFootHeight

      /**
       * * 流程二: 表头数据格式统一
       */
      const preRenderCfgTitle = getPreRenderCfgTitle(cfgTitle)
      state.titleColumns = preRenderCfgTitle

      /**
       * * 流程三: 等待…… titleColumns 渲染完成
       */
      nextTick().then(async () => {
        // * 预渲染表头
        const preRenderThead = document.querySelector(
          '.icr-preRenderPage #preRenderTable'
        )

        /**
         * * 流程四: 收集表头列渲染数据
         */
        const renderedTitleColumns = getRenderedTitleColumns(preRenderThead)

        /**
         * * 流程五: 优化表头列渲染数据, 生成新的数据结构
         */
        const treeHeightColumns = optimizeTitleColumns(
          cloneDeep(renderedTitleColumns),
          TitleColumnsHeightStrategy.bottom
        )
        state.treeColumns = treeHeightColumns
        state.theadHeight = treeHeightColumns.rowHeight + 1 // * 此处得到表格行高

        // console.log(cloneDeep(_that.treeColumns))

        /**
         * * 流程六: 更新表头项map中节点的布局数据
         */
        updateTitleColumnsLayoutData(state.treeColumns, treeColumnMap)

        // console.log("treeHeightColumns, treeColumnMap.entries(): ", treeHeightColumns, treeColumnMap.entries());
        /**
         * * 流程七: 获取数据行空模板
         */
        const dataRowTemp = getRenderRowDefault(cfgTitle) // 渲染行模板

        /**
         * * 流程八: 将原始的数据列表做一次扁平化处理
         */
        const fList = toFlatData(cfgData, { name: props.username }) // 处理过一次的扁平化 渲染数据列表

        /**
         * ? 原流程十二提前
         * * 流程十二: 将表头叶子节点分页
         * TODO 传入参数需要再整理
         */
        // const { pagesColumn: pagesLeafColumns, pagesInfo } = getPagesColumn(
        //   leafMap,
        //   cfgTitle,
        //   undefined,
        //   treeColumnMap
        // )

        // 使用 worker 重构 getPagesColumn 方法，节省主线程资源占用
        let pagesLeafColumns
        let pagesInfo

        try {
          await pool.terminate(true)
          const res = await pool.exec(getPagesColumnWorker, [
            [leafMap, cfgTitle, undefined, treeColumnMap],
            { pageBaseInfo }
          ])
          pagesLeafColumns = res.pagesColumn
          pagesInfo = res.pagesInfo
        } catch (error) {
          return
        }

        /**
         * * 流程九: 获取表格渲染数据列表
         */
        const renderDataList = resolveDataRowsAndValue(
          totalDataRows,
          dataRowTemp,
          fList,
          pagesInfo
        )
        // console.log('renderDataList: ', cloneDeep(renderDataList))
        state.tableList = renderDataList

        /**
         * * 流程十: 等待…… tableList 渲染完成
         */
        nextTick().then(async () => {
          /**
           * * 流程十一: 获取渲染数据每一行的高度
           */
          getRowRenderHeight(state.tableList)

          /**
           * * 流程十二：护理记录某行高度超出每页最大高度时，对该字符串进行分割
           */
          const maxRowHeight =
            pageBaseInfo.height -
            pageBaseInfo.margin.top -
            pageBaseInfo.margin.bottom -
            (state.theadHeight || 0) -
            (state.docFootHeight || 0) -
            (state.docHeadHeight || 0) // 行最大高度
          const promiseArr = []
          state.tableList.forEach((val, idx) => {
            const item2 = cloneDeep(val)
            const index2 = idx
            if (item2.height > maxRowHeight) {
              item2.rData.forEach((val, idx) => {
                if (
                  val.dictValue === 'yx-hljl' ||
                  val.dictValue === 'yx-bqgc' ||
                  val['hlcz-itemCode']?.includes('care_remark')
                ) {
                  promiseArr.push(getColArr(val, idx, index2, maxRowHeight)) // 分割字符串
                }
              })
            }
          })
          const promiseData = []
          for (let i = 0; i < promiseArr.length; i++) {
            const res = await promiseArr[i]
            promiseData.push(res)
          }
          let extraRowNum = 0

          promiseData.forEach(item => {
            if (item) {
              const tableListArr = [] // 保存tableList新增行的数组
              const tableListTmp = cloneDeep(
                state.tableList[item.index2 + extraRowNum]
              )
              item.valArr.forEach((item2, idx2) => {
                if (idx2 > 0) {
                  // 除原始行外，新增的那几行val置空
                  for (let i = 0; i < tableListTmp.rData.length; i++) {
                    tableListTmp.rData[i].val = ''
                  }
                }
                tableListTmp.height = item2.height
                tableListTmp.rData[item.index3].val = item2.label
                tableListArr.push(cloneDeep(tableListTmp))
              })
              state.tableList.splice(
                item.index2 + extraRowNum,
                1,
                ...tableListArr
              ) // 把tableList里超出行最大高度的那行替换成分割后的多行
              extraRowNum += tableListArr.length - 1
            }
          })

          /**
           * * 流程十三: 将叶子节点还原成正常的配置树节点
           */
          const pagesColumn = parseColumnListToTree(
            treeColumnMap,
            pagesLeafColumns
          )
          // console.log("pagesColumn: ", cloneDeep(pagesColumn));

          /**
           * * 优化流程: 处理分页表头叶子节点宽度不及父节点宽度 bug
           * * 流程改造: 最后一页的列需要拉伸占满A4纸张
           */
          const { pagesFixedWidth: pagesFixedColumnWidth, pagesStretchW } =
            optimizePagesColumnWidth(pagesColumn)
          // console.log('pagesFixedColumnWidth: ', pagesFixedColumnWidth)

          /**
           * * 流程十四: 格式化分页表头配置项的数据结构
           */
          const formattedPagesColumn = parseTitleColumns(pagesColumn)
          // console.log("formattedPagesColumn", cloneDeep(formattedPagesColumn))

          /**
           * * 流程十五: 处理表格数据横向分页
           */
          const pagesXData = getPagesXRenderList(
            pagesLeafColumns,
            state.tableList,
            pagesInfo,
            pagesStretchW
          )
          // console.log('pagesXData: ', pagesXData)

          /**
           * * 流程十五-2: medicalHistory分页
           */
          state.docTopExtendPages = getDocTopExtendPages(
            state.docData,
            undefined,
            {
              tableHeadHeight: state.theadHeight,
              docHeaderHeight: state.docHeadHeight,
              docFooterHeight: state.docFootHeight
            }
          )

          /**
           * * 流程十六: 计算表格数据纵向分割参数
           */
          const medicalHistoryHeight =
            state.docTopExtendPages.length > 0
              ? state.docTopExtendPages[state.docTopExtendPages.length - 1]
                  .length *
                  40 +
                40
              : 0
          const pagesYPagingInfo = getPagesYDataPagingInfo(
            state.tableList,
            undefined,
            {
              tableHeadHeight: state.theadHeight,
              docHeaderHeight: state.docHeadHeight,
              docFooterHeight: state.docFootHeight,
              medicalHistoryHeight
            }
          )

          /**
           * * 流程十七: 获取表格全部分页数据
           */
          const pagingDataList = getPagingDataList(pagesXData, pagesYPagingInfo)

          /**
           * * 流程十八: 处理表格数据行渲染宽度偏差
           * ! 该流程已在其他地方完成, 应移除
           * TODO 该流程在优化完成后, 已没有存在的意义
           */
          // const fixedPagesColumnWidth = fixedDataCellWidth(formattedPagesColumn);
          const fixedPagesColumnWidth = []

          /**
           * * 流程十九: 整合分页表头配置项和分页数据
           */
          const pagesColumnAndData = getPagesColumnAndRData(
            formattedPagesColumn,
            pagingDataList,
            fixedPagesColumnWidth,
            pagesFixedColumnWidth,
            pagesStretchW
          )
          // 插入顶部额外内容分页内容
          const rowListItem = cloneDeep(pagesColumnAndData[0].rowList)
          const extendArr = []
          state.docTopExtendPages.forEach((v, index) => {
            const item = {
              rowList: rowListItem.map(v => {
                v.rData = []
                return v
              }),
              docTopExtendPage: v
            }
            if (index < state.docTopExtendPages.length - 1) {
              extendArr.push(item)
            } else {
              pagesColumnAndData[0].docTopExtendPage = v
            }
          })
          state.subPagesConfigList = extendArr.concat(pagesColumnAndData)

          // 签名影响-时间排序
          state.subPagesConfigList.forEach(item => {
            item.rowList.forEach(citem => {
              citem.rData.sort((a, b) => {
                return (
                  Number(new Date(a.rData[0].val)) -
                  Number(new Date(b.rData[0].val))
                )
              })
            })
          })

          nextTick(() => {
            // document.querySelector('.multi-container').scrollTop =
            //   document.querySelector('.multi-container').scrollHeight
            emit('changeLoading2', false)
          })
        })
      })
    }

    /**
     * 获取分割字符串后的数组
     */
    function getColArr(val, idx, index2, maxRowHeight) {
      return new Promise(resolve => {
        const valArr = []
        const item3 = cloneDeep(val)
        const index3 = idx
        const key = 'dom' + '-' + index2 + '-' + index3
        set(state.computeString, key, {
          // 新增一个dom，用来判断字符串在指定宽度下的高度
          label: '',
          width: item3.width
        })
        let dom
        const getComputeString = i => {
          const str = item3.val.substring(i * 10, (i + 1) * 10) // 每次取10个字符
          if (str) {
            state.computeString[key].label += str // 把新取的字符拼接到总字符串
            state.refs[key].innerHTML = state.computeString[key].label // 对象里面套的对象，修改属性后dom不会重新渲染，所以直接获取dom修改innerHTML
            if (dom.clientHeight > maxRowHeight) {
              // 当前字符串高度超过最大行高， 把当前label和height保存下来，重置label和dom的html
              valArr.push({
                label: state.computeString[key].label.substring(
                  0,
                  state.computeString[key].label.length - 10
                ),
                height: maxRowHeight
              })
              state.computeString[key].label = ''
              state.refs[key].innerHTML = ''
              getComputeString(i)
            } else {
              getComputeString(++i) // 取下10个字符
            }
          } else {
            // 字符取完
            if (state.computeString[key].label) {
              // 剩余的字符放入valArr
              valArr.push({
                label: state.computeString[key].label,
                height: dom.clientHeight
              })
            }
            if (valArr.length > 1) {
              // valArr大于1说明行高超过最大行高
              resolve({
                index2: index2,
                index3: index3,
                valArr: valArr
              })
            } else {
              resolve(null)
            }
          }
        }
        const isComplete = () => {
          // 当dom渲染完成之后才开始执行
          dom = document.querySelector('.' + key)
          if (dom && state.refs[key]) {
            getComputeString(0)
          } else {
            setTimeout(() => {
              isComplete()
            }, 200)
          }
        }
        isComplete()
      })
    }

    // 获取顶部数据
    function getDocData() {
      state.docData = {
        doc: {},
        docItems: [],
        scoreRecord: [],
        respList: []
      }
      const startTime = props.activeDate[0]
      const endTime = props.activeDate[1]
      const params = {
        patientIdent: patCur.value.patientIdent,
        hospitalNumber: patCur.value.hospitalNumber,
        type: 12,
        endItemTime: endTime,
        startItemTime: startTime
      }
      Doc.getDocWithItemByParam(params).then(({ data }) => {
        state.docData.doc = data?.doc
        state.docData.docItems = data?.docItems
      })
      queryScoreRecord()
    }

    // 重症病情护理记录单评分查询
    function queryScoreRecord() {
      const startTime = props.activeDate[0]
      const endTime = props.activeDate[1]

      const params = {
        patientIdent: patCur.value.patientIdent,
        hospitalNumber: patCur.value.hospitalNumber,
        dataSource: 1,
        endTime: endTime,
        startTime: startTime
      }
      Doc.getScoreRecord(params).then(({ data }) => {
        state.docData.scoreRecord = data
      })
    }

    // 保存顶部数据
    function saveDocData() {
      const params = state.icrPartialPageRefs['0_0']?.getDocSaveParams()
      Doc.addOrModifyDocWithItem(params).then(({ data: res }) => {
        $message.success(`保存成功`)
      })
    }

    watch(
      patCur,
      val => {
        if (val && val.id !== state.lastPatCurId) {
          state.lastPatCurId = val.id
          initData()
        }
      },
      { immediate: true }
    )

    watch(
      () => props.activeDate,
      val => {
        setTimeout(() => {
          initData()
        }, 100)
      },
      { deep: true }
    )

    return {
      ...toRefs(state),
      initData,
      handleEdit,
      saveDocData,
      saveCellData,
      handleDialogShow
    }
  }
})
</script>

<style lang="scss" scoped>
#aiDoc {
  display: block;

  * {
    box-sizing: border-box;
  }
}

#preRenderDoc {
  float: left;
  margin-left: -9999px;
  font-size: 12px;
  box-sizing: border-box;

  .doc-header-area {
    // max-width: 1700px;
    // padding-left: 30px;
    // padding-right: 30px;
  }
}

.pages-row {
  display: block;
  white-space: nowrap;
}

.compute-box {
  float: left;
  margin-left: -9999px;
  font-size: 12px;
  line-height: 1.25;
  padding: 5px 1px;
  word-break: break-all;
  overflow-wrap: anywhere;
}
</style>
